﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SpeakupBackend.Themes;
using System.Collections;
using SpeakupBackend.Classes;
using TableParsers;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace SpeakupTests.SpeakupBackend.Themes.Group
{
    [TestClass]
    public class GroupThemeCollectionTest
    {
        [TestMethod]
        public void Create()
        {
            GroupThemeCollection collection = new GroupThemeCollection();

            foreach (GroupThemeName name in Enum.GetValues(typeof(GroupThemeName)))
            {
                foreach (Level level in Level.GetLevels())
                {
                    /* verify that object exits and is not null via 
                     * accessing any field */
                    Assert.IsFalse(collection[name, level].IsAttended);                    
                }
            }
        }

        [TestMethod]
        public void Indexers()
        {
            GroupThemeCollection collection = new GroupThemeCollection();

            foreach (Level level in Level.GetLevels())
            {
                foreach (GroupThemeName name in Enum.GetValues(typeof(GroupThemeName)))
                {
                    Assert.AreEqual(level, collection[name, level].Level);
                    Assert.AreEqual(name.ToString(), collection[name, level].Name);
                    Assert.AreEqual(name, collection[name, level].GroupThemeName);

                    Assert.AreEqual(level, collection[level, name].Level);
                    Assert.AreEqual(name.ToString(), collection[level, name].Name);
                    Assert.AreEqual(name, collection[level, name].GroupThemeName);
                }
            }

            foreach (Level level in Level.GetLevels())
            {
                foreach (GroupTheme theme in collection[level])
                {
                    Assert.AreEqual(level, theme.Level);                    
                }
            }

            foreach (GroupThemeName name in Enum.GetValues(typeof(GroupThemeName)))
            {
                foreach (GroupTheme theme in collection[name])
                {
                    Assert.AreEqual(name.ToString(), theme.Name);
                    Assert.AreEqual(name, theme.GroupThemeName);
                }
            }
        }

        int indexOf(Level level)
        {
            return level.LevelNumber - Level.MinValidLevelNumber;
        }

        int indexOf(GroupThemeName name)
        {
            return (int)name;
        }

        [TestMethod]
        public void GetEnumerator()
        {
            GroupThemeCollection themeCollection = new GroupThemeCollection();
            IEnumerable enumerable = themeCollection;

            int levelCount = Level.GetLevels().Count;
            int nameCount = Enum.GetValues(typeof(GroupThemeName)).Length;
            
            int[,] present =  new int[levelCount, nameCount];

            foreach (GroupTheme theme in enumerable)
            {
                present[indexOf(theme.Level), indexOf(theme.GroupThemeName)]++;
            }

            foreach (int counter in present)
            {
                Assert.AreEqual(1, counter);
            }
        }

        [TestMethod]
        public void GetGenericEnumerator()
        {
            GroupThemeCollection themeCollection = new GroupThemeCollection();

            int levelCount = Level.GetLevels().Count;
            int nameCount = Enum.GetValues(typeof(GroupThemeName)).Length;

            int[,] present = new int[levelCount, nameCount];

            foreach (GroupTheme theme in themeCollection)
            {
                present[indexOf(theme.Level), indexOf(theme.GroupThemeName)]++;
            }

            foreach (int counter in present)
            {
                Assert.AreEqual(1, counter);
            }
        }

        Class CreateAttendedClass(Level level, GroupThemeName name)
        {
            return new Class(0,
                new ClassName(name.ToString(), name.ToString(), GroupTheme.ValidClassType),
                new ClassTime(DateTime.Now.Date, TimeSpan.FromHours(12), TimeSpan.FromHours(13)),
                level.GetUnits().First(), ClassStatus.Attended, ClassAction.None);

        }

        class Counter
        {
            public int count = 0;
        }

        [TestMethod]
        public void PropertyChanged()
        {
            GroupThemeCollection collection = new GroupThemeCollection();
            Counter counter = new Counter();

            collection.PropertyChanged += (e, s) => counter.count++;

            foreach (GroupTheme theme in collection)
            {
                counter.count = 0;
                theme.AddClass(CreateAttendedClass(theme.Level, theme.GroupThemeName));
                Assert.AreEqual(1, counter.count);
            }            
        }

        [TestMethod]
        public void SaveLoad()
        {
            GroupThemeCollection collection = new GroupThemeCollection();

            Random rnd = new Random();
            foreach (GroupTheme theme in collection)
            {
                if (rnd.Next() % 2 == 1)
                {
                    theme.AddClass(CreateAttendedClass(theme.Level, theme.GroupThemeName));
                }                
            } 
            
            String file = Path.GetTempFileName();
            collection.Save(file);
            GroupThemeCollection deserialized = GroupThemeCollection.Load(file);
            
            
            foreach (GroupTheme theme in deserialized)
            {
                Assert.AreEqual(collection[theme.Level, theme.GroupThemeName].Classes.Count,
                                theme.Classes.Count);
            }
        }

        [TestMethod]
        public void SerializeDeserializePropertyChanged()
        {
            GroupThemeCollection collection = new GroupThemeCollection();

            String file = Path.GetTempFileName();
            collection.Save(file);

            GroupThemeCollection deserialized = GroupThemeCollection.Load(file);

            Counter counter = new Counter();
            deserialized.PropertyChanged += (e, s) => counter.count++;

            foreach (GroupTheme theme in deserialized)
            {
                counter.count = 0;
                theme.AddClass(CreateAttendedClass(theme.Level, theme.GroupThemeName));
                Assert.AreEqual(1, counter.count);
            } 
        }

        [TestMethod]
        public void SaveReload()
        {
            GroupThemeCollection original = new GroupThemeCollection();
            GroupThemeCollection reloaded = new GroupThemeCollection();

            Random rnd = new Random();
            foreach (Level level in Level.GetLevels())
            {
                foreach (GroupThemeName name in Enum.GetValues(typeof(GroupThemeName)))
                {
                    GroupTheme theme;
                    if (rnd.Next() % 2 == 1)
                    {
                        theme = original[level, name];
                        theme.AddClass(CreateAttendedClass(theme.Level, theme.GroupThemeName));

                        theme = reloaded[level, name];
                        theme.AddClass(CreateAttendedClass(theme.Level, theme.GroupThemeName));
                    }
                }
            }

            String file = Path.GetTempFileName();
            original.Save(file);
            reloaded.ReloadFrom(file);

            foreach (Level level in Level.GetLevels())
            {
                foreach (GroupThemeName name in Enum.GetValues(typeof(GroupThemeName)))
                {
                    Assert.AreEqual(original[level, name].Classes.Count, reloaded[level, name].Classes.Count);
                    Assert.AreEqual(original[level, name].IsAttended, reloaded[level, name].IsAttended);
                }
            }
        }

        [TestMethod]
        public void SaveReloadPropertyChanged()
        {
            GroupThemeCollection reloaded = new GroupThemeCollection();
            Counter counter = new Counter();

            reloaded.PropertyChanged += (s,e) => counter.count++;

            List<GroupTheme> oldThemes = reloaded.ToList();

            String file = Path.GetTempFileName();
            reloaded.Save(file);
            reloaded.ReloadFrom(file);

            //verify that old themes are not subscribed anymore
            counter.count = 0;
            foreach (GroupTheme theme in oldThemes)
            {
                theme.AddClass(CreateAttendedClass(theme.Level, theme.GroupThemeName));
            }
            Assert.AreEqual(0, counter.count);

            //verify new theme are subscribed 
            foreach (GroupTheme theme in reloaded)
            {
                counter.count = 0;
                theme.AddClass(CreateAttendedClass(theme.Level, theme.GroupThemeName));
                Assert.AreEqual(1, counter.count);
            }
        }

     
    }
}
